package cn.bytest.netty.code;

import cn.bytest.netty.NettyChannel;
import cn.bytest.netty.serialize.ChannelBufferInput;
import cn.bytest.netty.serialize.ChannelBufferOutput;
import cn.bytets.rpc.api.Channel;
import cn.bytets.rpc.api.code.BytesUtils;
import cn.bytets.rpc.api.code.ChannelByteBuf;
import cn.bytets.rpc.api.code.Codec;
import cn.bytets.rpc.api.exchange.DefaultFuture;
import cn.bytets.rpc.api.message.Request;
import cn.bytets.rpc.api.message.Response;
import cn.bytets.rpc.api.message.RpcInvocation;
import cn.bytets.rpc.api.serialize.ObjectInput;
import cn.bytets.rpc.api.serialize.ObjectOutput;
import cn.bytets.rpc.api.serialize.RpcSerialize;

import java.io.IOException;

public class SpeedCodec implements Codec {

    private RpcSerialize serialize;

    @Override
    public void encode(Object msg, ChannelByteBuf byteBuf, RpcSerialize serialize, Channel channel) {
        this.serialize = serialize;
        if (msg instanceof Request){
            encode((Request)msg,byteBuf,0,channel);
        } else if (msg instanceof Response){
            encode((Response) msg,byteBuf,1,channel);
        } else {
            boolean isString = msg instanceof String;
            /**普通的消息*/
            encode(new Request(msg),byteBuf,isString?3:0,channel);
        }
    }
    @Override
    public Object decoder(ChannelByteBuf byteBuf,RpcSerialize serialize,Channel channel) throws IOException, ClassNotFoundException {
        this.serialize = serialize;
        int readableBytes = byteBuf.readableBytes();
        byte[] header = new byte[Math.min(readableBytes,BytesUtils.HEADER_LENGTH)];
        byteBuf.readBytes(header);
        return decoder(byteBuf,header,readableBytes,channel);
    }
    /**
     *
     * @param id
     * @param ResultType 数据请求类型 0 request 1 Response
     * @return
     */
    private byte[] getHeader(long id,int ResultType){
        byte[] header = new byte[BytesUtils.HEADER_LENGTH];
        BytesUtils.short2bytes(BytesUtils.MAGIC,header);
        BytesUtils.bytesRequestId(id,header,-1);
        BytesUtils.bytes(header,2,ResultType);
        return header;
    }
    /**
     *
     * @param request 需要编码的对象
     * @param byteBuf Netty byteBuf
     * @param type 0 request 1 Response
     */
    private void encode(Request request, ChannelByteBuf byteBuf,int type,Channel channel)  {
        encode(request.getData(),byteBuf,type,channel,request.getId());
        channel.setRequest(request);
    }
    private void encode(Response response, ChannelByteBuf byteBuf,int type,Channel channel)  {
        encode(response,byteBuf,type,channel,response.getId());
    }
    private void encode(Object data, ChannelByteBuf byteBuf,int type,Channel channel,long id)  {
        /**
         * 消息头 16位长度
         * 1. 0-1 魔数高低位
         * 2. 2 请求方式 request/response
         * 3. 4-11 request Id
         * 4. 12-15 数据长度
         */
        byte[] header = getHeader(id,type);
        /**
         * 标记起始位置
         */
        int startWriteIndex = byteBuf.writerIndex();

        byteBuf.writeIndex(startWriteIndex+header.length);
        ChannelBufferOutput output = null;
        try {
            if (type==3){
                byteBuf.writeBytes(((String)data).getBytes());
            } else {
                output = new ChannelBufferOutput(byteBuf);
                ObjectOutput out = this.serialize.serialize(output);
                out.writeObject(data);
                out.flushBuffer();
                output.flush();
            }
            /**
             * 数据长度
             */
            int len = byteBuf.writerIndex()-byteBuf.readerIndex()-header.length;
            BytesUtils.bytesDataLen(header,len,-1);
            byteBuf.writeIndex(startWriteIndex);
            byteBuf.writeBytes(header);
            byteBuf.writeIndex(startWriteIndex+header.length+len);
        } catch (Exception e){
            if (0==type) {
                DefaultFuture future = DefaultFuture.getFuture(id);
                future.completeExceptionally(e);
            }
        } finally {
            if (null!=output){
                try {
                    output.close();
                    output = null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }


    private Object decoder(ChannelByteBuf byteBuf, byte[] header, int readableBytes,Channel channel) throws IOException, ClassNotFoundException {
        /**
         * 校验数据的安全性(这里测试不作校验)
         */
        int len = BytesUtils.bytesDataLen2int(header, -1);
        long id = BytesUtils.bytesRequestId2Long(header, -1);
        /**
         * 数据请求类型
         */
        int type = BytesUtils.getBytes(header,2);
        ChannelBufferInput input = null;
        try{
            input = new ChannelBufferInput(byteBuf,len/*readableBytes-header.length*/);
            ObjectInput deserialize = serialize.deserialize(input);
            //request
            if(0==type) {
                return new Request(id, deserialize.readObject(RpcInvocation.class));
            } else if (1==type){
                //response
                Response data = deserialize.readObject(Response.class);
                data.setId(id);
                return data;
            }
        } catch (IOException | ClassNotFoundException e){
            throw e;
        } finally {
            if (null!=input){
                try {
                    input.close();
                    input = null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}
